/**
 * 思路整理
 * 优先设置材质包等地形
 * 设置人物初始地点
 * 设置地形碰撞思路
 * 设置公共角色下坠逻辑
 * 人物动作之跳跃
 * 每帧动画
 */
import wall from '@/assets/imgs/wall.png'
import role from '@/assets/imgs/role.png'
import config from '@/config/index'
import { computeY, computeH } from '@/utils/index'
interface wall {
    pointStartX: number,
    pointStartY: number,
    wallW: number,
    wallH: number,
}

export default class MarioWorld {
    private pixel: number = 10 // 个体最小单位大小，其余只能为他的倍数
    private ctx: CanvasRenderingContext2D = <CanvasRenderingContext2D> {} // 展示画布
    private ctxW: number = config.sceneW
    private ctxH: number = config.sceneH
    private cacheCtx: CanvasRenderingContext2D = <CanvasRenderingContext2D> {} // 缓冲画布
    private cacheCanvas: HTMLCanvasElement = <HTMLCanvasElement> {}
    private wallList: wall[] = [
        {
            pointStartX: 0,
            pointStartY: computeY(0),
            wallW: 800,
            wallH: computeH(80), // 向下
        },
        {
            pointStartX: 0,
            pointStartY: computeY(80),
            wallW: 50,
            wallH: computeH(80), // 向下
        }
    ] // 墙体数据
    private roleX: number = 50 // 角色X坐标
    private roleY: number = computeY(80) // 角色Y坐标
    private roleW: number = 50 // 人物宽度
    private roleH: number = computeH(50) // 人物高度
    private roleMove: number = 3 // 人物移动单元
    private roleJumpUnit: number = 80 // 人物跳跃高度
    private roleLoading: boolean = false // 是否在跳跃中
    // 初始化
    public createCanvas(id: string) {
        const canvas = document.createElement('canvas')
        canvas.setAttribute('width', `${this.ctxW}px`)
        canvas.setAttribute('height', `${this.ctxH}px`)
        const dom = document.getElementById(id)
        if(dom) {
            dom.append(canvas)
            const ctx = canvas.getContext('2d');
            this.ctx = ctx as CanvasRenderingContext2D
        }
        // 创建临时canvas做缓冲
        const cacheCanvas = document.createElement('canvas')
        cacheCanvas.setAttribute('width', `${this.ctxW}px`)
        cacheCanvas.setAttribute('height', `${this.ctxH}px`)
        this.cacheCanvas = cacheCanvas
        this.cacheCtx = cacheCanvas.getContext('2d') as CanvasRenderingContext2D;
    }

    // 绘制所有单元绘制
    public async drawAllUnit() {
        this.cacheCtx.clearRect(0, 0, this.ctxW, this.ctxH)
        await this.drawBackgroud()
        await this.drawRole()
        const image = this.canvasToImg(this.cacheCanvas)
        image.onload = ()=>{
            this.ctx.clearRect(0, 0, this.ctxW, this.ctxH)
            this.ctx.rect(0, 0, this.ctxW, this.ctxH)
            this.ctx.fillStyle = '#eeeeee';
            this.ctx.fill()
            this.ctx.drawImage(image, 0, 0, this.ctxW, this.ctxH)
        }
    }

    // 画布转图片对象
    private canvasToImg(canvas: HTMLCanvasElement) {
        const img = new Image()
        img.src = canvas.toDataURL('image/png')
        return img
    }

    // 生成墙图形
    public async drawBackgroud() {
        for(let i = 0; i < this.wallList.length; i++) {
            const ele = this.wallList[i]
            await this.drawTexture(wall, ele.pointStartX, ele.pointStartY, ele.wallW, ele.wallH)
        }
    }
    // 绘制纹理
    private drawTexture(src: string, x: number, y: number, w: number, h: number) {
        return new Promise((resolve, reject)=>{
            const img = new Image();   // 创建一个<img>元素
            img.src = src; // 设置图片源地址
            img.onload = ()=>{
                // 固定纹理的宽高
                let tempCanvas: HTMLCanvasElement = document.createElement('canvas');
                tempCanvas.width = this.pixel;
                tempCanvas.height = this.pixel;
                let tempCtx: CanvasRenderingContext2D = <CanvasRenderingContext2D> tempCanvas.getContext('2d');
                tempCtx.drawImage(img, 0, 0, this.pixel, this.pixel);
                let pat: CanvasPattern = <CanvasPattern> this.cacheCtx.createPattern(tempCanvas,"repeat");
                this.cacheCtx.rect(x,y,w,h);
                this.cacheCtx.fillStyle = pat;
                this.cacheCtx.fill()
                resolve(true)
            }
            img.onerror = ()=>void reject(false);
        })
    }

    // 打开人物控制器
    public roleController() {
        document.onkeydown = (e)=>{    //对整个页面监听  
            const keyNum = e || window.event || arguments.callee.caller.arguments[0];       //获取被按下的键值  
            //判断如果用户按下了回车键（keycody=13）  
            const key = keyNum.key
            if(key === 'w') {
                // 跳跃处理
                this.roleLoading = true
                this.jumpHandler(this.roleY, this.roleY + this.roleJumpUnit)
            }
            if(key === 's') {

            }
            if(key === 'a') {
                const newX = this.roleX - this.roleMove
                const collision = this.collisionJudge(newX, this.roleY)
                if(collision) {
                    this.roleX = newX
                    this.drawAllUnit()
                }
            }
            if(key === 'd') {
                const newX = this.roleX + this.roleMove
                const collision = this.collisionJudge(newX, this.roleY)
                if(collision) {
                    this.roleX = newX
                    this.drawAllUnit()
                }
            }
        }
    }

    // 跳跃方法
    private jumpHandler(start: number, end: number) {
        const speed = 5
        window.jumpInterval = setInterval(()=>{
            let newY = start + speed
            if(newY > end) {
                // 到跳跃顶点
                newY = end
                // 反转
                clearInterval(window.jumpInterval)
                // 掉落下降
                this.addSpeed(newY)
            }
            this.roleY = newY
            this.drawAllUnit()
        }, 100)
    }
    // 加速度运动
    private addSpeed(start: number) {
        const speed = 5
        window.jumpInterval = setInterval(()=>{
            let newY = start - speed
            // 碰撞后停止
            const collision = this.collisionJudge(this.roleX, newY)
            if(collision) {
                clearInterval(window.jumpInterval)
                this.roleLoading = false
            }
            this.roleY = newY
            this.drawAllUnit()
        }, 100)
    }

    /**
     * 物体碰撞判断 -- 角色坐标加角色的宽高，要都小于墙体坐标或者大于墙体坐标加宽或者高
     * @param x 角色下一次移动的x坐标
     * @param y 角色下一次移动的y坐标
     * @returns 是否没碰撞
     */
    private collisionJudge(x: number, y: number) {
        let result: boolean = true
        for(let i: number = 0; i < this.wallList.length; i++) {
            const ele = this.wallList[i]
            const pointStartX = ele.pointStartX
            const pointStartY = ele.pointStartY
            const pointEndX = ele.pointStartX + ele.wallW
            const pointEndY = ele.pointStartY - ele.wallH
            console.log(x, y, pointStartX, pointStartY, pointEndX, pointEndY)
            console.log(x >= pointStartX && x < pointEndX && y >= pointStartY && y < pointEndY)
            // 排除 X 轴和 Y 轴上坐标尾部贴合情况
            if(x >= pointStartX && x < pointEndX && y >= pointStartY && y < pointEndY) {
                result = false
                return result
            }
        }
        return result
    }

    // 绘制人物
    public async drawRole() {
        await this.drawImageFun(role, this.roleX, this.roleY, this.roleW, this.roleH)
    }

    /**
     * 绘制图片的方法
     * @param src 图片地址
     * @param x x坐标
     * @param y y坐标
     * @param w 宽度
     * @param h 高度
     * @returns 
     */
     private drawImageFun(src: string, x: number, y: number, w: number, h: number) {
        return new Promise((resolve, reject)=>{
            const img = new Image();   // 创建一个<img>元素
            img.onload = ()=>{
                this.cacheCtx.drawImage(img, x, y, w, h)//绘制图片
                resolve(true)
            }
            img.onerror = ()=>void reject(false);
            img.src = src; // 设置图片源地址
        })
    }
}